package com.majun.config.filter5;

import com.alibaba.fastjson2.JSON;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.support.StandardServletMultipartResolver;
import org.springframework.web.util.ContentCachingResponseWrapper;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 记录请求日志
 */
public class RequestLogFilter5 extends HttpFilter {

    static final Logger log = LoggerFactory.getLogger(RequestLogFilter5.class);

    /**
     * 
     */
    private static final long serialVersionUID = 8991118181953196532L;


    @Override
    protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        
        // Wrapper 封装 Request 和 Response
        MyContentCachingRequestWrapper cachingRequest = new MyContentCachingRequestWrapper(request);
        ContentCachingResponseWrapper cachingResponse = new ContentCachingResponseWrapper(response);

//        // 继续执行请求链
//        chain.doFilter(cachingRequest, cachingResponse);

        /**
         * 在请求完成后记录请求、响应日志
         */
        // 请求方法
        String method = request.getMethod();
        // URI
        String url = request.getRequestURL().toString();
        // 请求体
        byte[] requestContent = cachingRequest.getBody();

//        String input = ByteSource.wrap(cachingRequest.getContentAsByteArray())
//                .asCharSource(StandardCharsets.UTF_8).read();
//        System.err.println(input);

//        final String requestParams = getRequestParams(request);

        final String requestIp = getRequestIp(request);

        String requestBody = new String(requestContent);
        if (StringUtils.isNotBlank(requestBody)){
            requestBody = requestBody.replaceAll("\n|\r", "");
        }

//        // 继续执行请求链
//        chain.doFilter(cachingRequest, cachingResponse);

        // 输出请求体
//        String requestBody = "";
        String requestContentType = request.getHeader(HttpHeaders.CONTENT_TYPE);


        if (requestContentType != null){
//			xml json
            if (requestContentType.startsWith(MediaType.APPLICATION_JSON_VALUE) || requestContentType.startsWith(MediaType.APPLICATION_XML_VALUE)){
//                requestBody = getRequestBody(request);
//                final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(requestBody.getBytes(StandardCharsets.UTF_8));
//                request = new HttpServletRequestWrapper(request) {
//                    @Override
//                    public ServletInputStream getInputStream() throws IOException {
//                        return new ByteArrayServletInputStream(byteArrayInputStream);
//                    }
//                };
                requestBody = new String(requestContent);
//		    普通表单提交
            }else if (requestContentType.startsWith(MediaType.APPLICATION_FORM_URLENCODED_VALUE)){
                requestBody = getRequestParams(request);;
//			文件表单提交
            }else if (requestContentType.startsWith(MediaType.MULTIPART_FORM_DATA_VALUE)){
                requestBody = getFileFormParam(request);
            }
        }

//        log.info("Request => {} {} requestbody:{} requestParams:{} requestIp:{} ", method, url, requestBody, requestParams, requestIp);
        log.info("Request =====> method:[{}] url:[{}] requestbody:[{}] requestIp:[{}] ", method, url, requestBody, requestIp);
//        log.info("Request =====> method:[{}] url:[{}] requestbody:[{}] requestIp:[{}] ", method, url, requestBody1, requestIp);


        // 继续执行请求链
        chain.doFilter(cachingRequest, cachingResponse);

        // 响应状态
        int status = response.getStatus();
        // 响应体
        byte[] responseContent = cachingResponse.getContentAsByteArray();
        
        log.info("Response <===== [{}] [{}]", status, new String(responseContent));
        
        /**
         * 把缓存的响应数据，响应给客户端
         */
        // 这一步很重要，把缓存的响应内容，输出到客户端
        cachingResponse.copyBodyToResponse();
    }

    private String getRequestParams(final HttpServletRequest request) {
        Map<String, String[]> requestParams = request.getParameterMap();
        final List<String> pairs = Lists.newArrayList();
        if (MapUtils.isNotEmpty(requestParams)) {
            for (final Map.Entry<String, String[]> entry : requestParams.entrySet()) {
                final String name = entry.getKey();
                final String[] value = entry.getValue();
                if (value == null) {
                    pairs.add(name + "=");
                } else {
                    for (final String v : value) {
                        pairs.add(name + "=" + StringUtils.trimToEmpty(v));
                    }
                }
            }
        }
        String requestParamsStr = CollectionUtils.isEmpty(pairs) ? StringUtils.EMPTY : String.join("&", pairs);
        if (StringUtils.equalsIgnoreCase(request.getContentType(), MediaType.APPLICATION_FORM_URLENCODED_VALUE)) {
            try {
                requestParamsStr = URLDecoder.decode(requestParamsStr, StandardCharsets.UTF_8.name());
            } catch (UnsupportedEncodingException ignored) {
            }
        }
        return requestParamsStr;
    }

    private String getRequestIp(final HttpServletRequest request) {
        String ip = request.getHeader("X-Real-IP");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Forwarded-For");// 这是一个可以伪造的头
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
            }
        }
        // 最后一个为RemoteAddr
        int pos = ip.lastIndexOf(',');
        if (pos >= 0) {
            ip = ip.substring(pos);
        }
        if ("0:0:0:0:0:0:0:1".equals(ip)) {
            ip = "127.0.0.1";
        }
        return ip;
    }

    private static String toJson(Object object){
        String jsonString = JSON.toJSONString(object, "yyyy-MM-dd HH:mm:ss");
        return jsonString;
    }

    private String getFileFormParam(HttpServletRequest request) {
        MultipartResolver resolver = new StandardServletMultipartResolver();
        MultipartHttpServletRequest mRequest = resolver.resolveMultipart(request);

        Map<String,Object> param = new HashMap<>();
        Map<String,String[]> parameterMap = mRequest.getParameterMap();
        if (!parameterMap.isEmpty()){
            param.putAll(parameterMap);
        }
        Map<String, MultipartFile> fileMap = mRequest.getFileMap();
        if(!fileMap.isEmpty()){
            for (Map.Entry<String, MultipartFile> fileEntry : fileMap.entrySet()) {
                MultipartFile file = fileEntry.getValue();
                param.put(fileEntry.getKey(), file.getOriginalFilename()+ "(" + file.getSize()+" byte)");
            }
        }
        String jsonString = JSON.toJSONString(param);
        return jsonString;
    }

//    private String getRequestBody(HttpServletRequest request) {
//        String requestBody = "";
//        ContentCachingRequestWrapper wrapper = WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class);
//        if (wrapper != null) {
//            try {
//                requestBody = IOUtils.toString(wrapper.getContentAsByteArray(), wrapper.getCharacterEncoding());
//            } catch (IOException e) {
//            }
//        }
//        return requestBody;
//    }

}